﻿using COSXML.Auth;
using COSXML.Model.Bucket;
using COSXML.Model.Object;
using COSXML.Transfer;
using COSXML;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using System;
using UnityEditor;
using UnityEngine;
using System.Diagnostics;
using ZyGame.Editor.CloudBuilder;
using UnityEngine.Networking;
using System.Security.Policy;
using static COSXML.Model.Tag.ListAllMyBuckets;

namespace ZyGame.Editor.CloudBuilder
{
    [PathOptions("ProjectSettings/CloudBuildOptions.asset", PathOptions.Localtion.Project)]
    public class CloudBuildOptions : Config<CloudBuildOptions>
    {
        public string url;
        public string pid;
        public string output;
        public string SecretId;
        public string SecretKey;
        public string ap;
        public string bucket;

        public void OnGUI()
        {
            GUILayout.BeginHorizontal();
            GUILayout.Label("Output", GUILayout.Width(150));
            if (instance.output.IsNullOrEmpty())
            {
                instance.output = Application.dataPath;
            }
            if (EditorGUILayout.LinkButton(instance.output))
            {
                string temp = EditorUtility.OpenFolderPanel("选择输出文件夹", instance.output, Application.dataPath);
                if (temp.Equals(instance.output) is false)
                {
                    instance.output = temp;
                    Save();
                }
            }
            GUILayout.EndHorizontal();

            GUILayout.BeginHorizontal();
            GUILayout.Label("Url", GUILayout.Width(150));
            string url = GUILayout.TextField(instance.url);
            if (url.IsNullOrEmpty() is false && url.Equals(instance.url) is false)
            {
                instance.url = url;
                Save();
            }
            GUILayout.EndHorizontal();

            GUILayout.BeginHorizontal();
            GUILayout.Label("Project Id", GUILayout.Width(150));
            string project = GUILayout.TextField(instance.pid);
            if (project.IsNullOrEmpty() is false && project.Equals(instance.pid) is false)
            {
                instance.pid = project;
                Save();
            }
            GUILayout.EndHorizontal();

            GUILayout.BeginHorizontal();
            GUILayout.Label("SecretId", GUILayout.Width(150));
            string SecretId = GUILayout.TextField(instance.SecretId);
            if (SecretId.IsNullOrEmpty() is false && SecretId.Equals(instance.SecretId) is false)
            {
                instance.SecretId = SecretId;
                Save();
            }
            GUILayout.EndHorizontal();

            GUILayout.BeginHorizontal();
            GUILayout.Label("SecretKey", GUILayout.Width(150));
            string SecretKey = GUILayout.TextField(instance.SecretKey);
            if (SecretKey.IsNullOrEmpty() is false && SecretKey.Equals(instance.SecretKey) is false)
            {
                instance.SecretKey = SecretKey;
                Save();
            }
            GUILayout.EndHorizontal();

            GUILayout.BeginHorizontal();
            GUILayout.Label("Region", GUILayout.Width(150));
            string region = GUILayout.TextField(instance.ap);
            if (region.IsNullOrEmpty() is false && region.Equals(instance.ap) is false)
            {
                instance.ap = region;
                Save();
            }
            GUILayout.EndHorizontal();

            GUILayout.BeginHorizontal();
            GUILayout.Label("Bucket", GUILayout.Width(150));
            string bucket = GUILayout.TextField(instance.bucket);
            if (bucket.IsNullOrEmpty() is false && bucket.Equals(instance.bucket) is false)
            {
                instance.bucket = bucket;
                Save();
            }
            GUILayout.EndHorizontal();
        }
    }
    public enum TaskState
    {
        Waiting,
        Stoping,
        Completion,
    }
    public enum Platform
    {
        Android,
        IOS,
        Windows,
        WebGL,
        All,
    }
    public class BuildData
    {
        public string id { get; set; }
        public string pid { get; set; }
        public string bundleName { get; set; }
        public List<string> files { get; set; }
        public DateTime time { get; set; }
        public TaskState State { get; set; }
        public Platform platform { get; set; }
        public string download { get; set; }
        public bool _rw { get; set; }
        public bool _bs { get; set; }
        public bool _ani { get; set; }
        public string _texture { get; set; }
        public bool _alpha { get; set; }
        public bool _minimap { get; set; }

        public BuildTarget GetBuildTarget()
        {
            return platform switch
            {
                Platform.Windows => BuildTarget.StandaloneWindows,
                Platform.WebGL => BuildTarget.WebGL,
                Platform.Android => BuildTarget.Android,
                Platform.IOS => BuildTarget.iOS,
                _ => EditorUserBuildSettings.activeBuildTarget
            };
        }

        public Platform GetPlatform()
        {
            return EditorUserBuildSettings.activeBuildTarget switch
            {
                BuildTarget.StandaloneWindows => Platform.Windows,
                BuildTarget.WebGL => Platform.WebGL,
                BuildTarget.Android => Platform.Android,
                BuildTarget.iOS => Platform.IOS,
                _ => Platform.All
            };
        }
    }

    public sealed class Api
    {
        public static UnityWebRequest NewBuild(BuildData buildData)
        {
            string url = $"{CloudBuildOptions.instance.url}build/new";
            string body = Newtonsoft.Json.JsonConvert.SerializeObject(buildData);
            UnityWebRequest request = UnityWebRequest.Post(url, body);
            request.SetRequestHeader("Content-Type", "application/json");
            request.uploadHandler = new UploadHandlerRaw(body.GetBytes());
            return request;
        }

        public static UnityWebRequest GetBuildList(BuildTarget build)
        {
            Platform platform = build switch
            {
                BuildTarget.Android => Platform.Android,
                BuildTarget.StandaloneWindows => Platform.Windows,
                BuildTarget.WebGL => Platform.WebGL,
                BuildTarget.iOS => Platform.IOS,
                _ => Platform.All,
            };
            string url = $"{CloudBuildOptions.instance.url}build/list?pid=all&platform={(int)platform}";
            UnityWebRequest request = UnityWebRequest.Get(url);
            request.SetRequestHeader("Content-Type", "application/json");
            return request;
        }

        public static UnityWebRequest GetFileDownloadRequest(string path)
        {
            if (path.StartsWith("http"))
            {
                return UnityWebRequest.Get(path);
            }
            string bucket = CloudBuildOptions.instance.bucket;
            string ap = CloudBuildOptions.instance.ap;
            UnityWebRequest request = UnityWebRequest.Get($"https://{bucket}.cos.{ap}.myqcloud.com/{path}");
            return request;
        }

        public static UnityWebRequest GetCompletionRequest(BuildData buildData)
        {
            UnityWebRequest request = UnityWebRequest.Get($"{CloudBuildOptions.instance.url}build/completion?pid={buildData.pid}&id={buildData.id}&platform={buildData.GetPlatform()}");
            request.SetRequestHeader("Content-Type", "application/json");
            return request;
        }
    }
}
namespace ZyGame.Editor.Tools
{
    public sealed class COS
    {
        private static CosXmlServer cosXml;
        private static void EnsureInitializedCos()
        {
            if (cosXml is not null)
            {
                return;
            }
            string secretId = CloudBuildOptions.instance.SecretId;
            string secretKey = CloudBuildOptions.instance.SecretKey;
            string region = CloudBuildOptions.instance.ap;
            CosXmlConfig config = new CosXmlConfig.Builder()
                .SetRegion(region)
                .SetDebugLog(true)
                .Build();

            long keyDurationSecond = 600;
            QCloudCredentialProvider qCloudCredentialProvider = new DefaultQCloudCredentialProvider(secretId, secretKey, keyDurationSecond);
            cosXml = new CosXmlServer(config, qCloudCredentialProvider);
        }

        internal static void PutBucket(string bucket)
        {
            try
            {
                EnsureInitializedCos();
                PutBucketRequest request = new PutBucketRequest(bucket);
                PutBucketResult result = cosXml.PutBucket(request);

                Console.WriteLine(result.GetResultInfo());
            }
            catch (COSXML.CosException.CosServerException serverEx)
            {
                if (serverEx.statusCode != 409)
                {
                    throw serverEx;
                }
                else
                {
                    Console.WriteLine("Bucket Already exists.");
                }
            }
        }

        internal static void DeleteBucket(string bucket)
        {
            EnsureInitializedCos();
            DeleteBucketRequest request = new DeleteBucketRequest(bucket);

            DeleteBucketResult result = cosXml.DeleteBucket(request);

            Console.WriteLine(result.GetResultInfo());
        }

        internal static void PutObject(string bucket, string cosPath, string path)
        {
            EnsureInitializedCos();
            try
            {
                PutObjectRequest uploadTask = new PutObjectRequest(bucket, cosPath, path);
                PutObjectResult result = cosXml.PutObject(uploadTask);

            }
            catch (Exception e)
            {
                Client.Console.WriteLine(e);
            }
        }

        internal static void UploadDirectory(string bucket, string path, Action<float> progress = null)
        {
            EnsureInitializedCos();
            TransferConfig transferConfig = new TransferConfig();
            TransferManager transferManager = new TransferManager(cosXml, transferConfig);
            var files = Directory.GetFiles(path);
            var tasks = new List<Task>();
            foreach (var file in files)
            {
                String cosPath = new FileInfo(file).Name;
                COSXMLUploadTask uploadTask = new COSXMLUploadTask(bucket, cosPath);
                uploadTask.SetSrcPath(file);
                uploadTask.progressCallback = delegate (long completed, long total)
                {
                    progress?.Invoke(completed * 100.0f / total);
                };
                tasks.Add(transferManager.UploadAsync(uploadTask));
            }

            try
            {
                Task.WaitAll(tasks.ToArray());
                Console.WriteLine("Upload Directory Complete");
            }
            catch (AggregateException e)
            {
                Console.WriteLine("\nThe following exceptions have been thrown by WaitAll(): (THIS WAS EXPECTED)");
                for (int j = 0; j < e.InnerExceptions.Count; j++)
                {
                    Console.WriteLine("\n-------------------------------------------------\n{0}", e.InnerExceptions[j].ToString());
                }
            }

        }

        internal static async Task GetObject(string bucket, string cosKey, string localtion, Action<float> progress = null)
        {
            EnsureInitializedCos();
            TransferConfig transferConfig = new TransferConfig();
            TransferManager transferManager = new TransferManager(cosXml, transferConfig);
            String cosPath = cosKey;
            string localDir = Path.GetDirectoryName(localtion);
            string localFileName = Path.GetFileName(localtion);
            COSXMLDownloadTask downloadTask = new COSXMLDownloadTask(bucket, cosPath, localDir, localFileName);
            downloadTask.progressCallback = delegate (long completed, long total)
            {
                progress?.Invoke(completed * 100.0f / total);
            };
            try
            {
                COSXMLDownloadTask.DownloadTaskResult result = await transferManager.DownloadAsync(downloadTask);
                Console.WriteLine(result.GetResultInfo());
                string eTag = result.eTag;
            }
            catch (Exception e)
            {
                Console.WriteLine("CosException: " + e);
            }
        }

        internal static void DeleteObject(string bucket, string cosKey)
        {
            EnsureInitializedCos();
            DeleteObjectRequest request = new DeleteObjectRequest(bucket, cosKey);
            DeleteObjectResult result = cosXml.DeleteObject(request);
            Console.WriteLine(result.GetResultInfo());
        }
    }
}
